/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __FILE_DOWNLOAD_H_
#define __FILE_DOWNLOAD_H_
extern "C" {
#include "curl/curl.h"
#include "curl/easy.h"
}
#include <cstring>
#include <cstdint>
#include <memory>

#include <iostream>
#include "securec.h"
class FileDownload {
public:
    explicit FileDownload(std::string url) : url_(url)
    {
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl_ = curl_easy_init();
    }
    ~FileDownload()
    {
        if (curl_ != nullptr) {
            curl_easy_cleanup(curl_);
            curl_ = nullptr;
        }
        curl_global_cleanup();
    }

    bool Cancel()
    {
        return false;
    }
    bool SetHeaders(void *headers)
    {
        return true;
    }
    bool Start()
    {
        memoryBuffer_ = std::make_shared<Buffer>();
        curl_easy_setopt(curl_, CURLOPT_URL, url_.c_str());
        curl_easy_setopt(curl_, CURLOPT_NOBODY, 1L);
        curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, GetHeaderData);
        curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L);

        CURLcode code = curl_easy_perform(curl_);
        if (CURLE_OK != code) {
            return false;
        }
        double size = 0.0;
        curl_easy_getinfo(curl_, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size);
        memoryBuffer_->size = size;
        memoryBuffer_->data = std::shared_ptr<uint8_t[]>(new uint8_t[memoryBuffer_->size], [](uint8_t *data){
            delete [] data;
            data = nullptr;
        });

        curl_easy_reset(curl_);
        curl_easy_setopt(curl_, CURLOPT_HTTPGET, 1L);
        curl_easy_setopt(curl_, CURLOPT_NOBODY, 0L);
        curl_easy_setopt(curl_, CURLOPT_URL, url_.c_str());
        curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, GetCurlData);
        curl_easy_setopt(curl_, CURLOPT_WRITEDATA, memoryBuffer_.get());
        curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, 1L);
    
        code = curl_easy_perform(curl_);
        if (CURLE_OK != code) {
            return false;
        }
        return true;
    }
    std::pair<std::shared_ptr<uint8_t[]>, uint32_t> GetData()
    {
        return std::make_pair(memoryBuffer_->data, memoryBuffer_->size);
    }
private:
    struct Buffer {
        std::shared_ptr<uint8_t[]> data{nullptr};
        size_t size{0};
        size_t filled{0};
    };
    static size_t GetHeaderData(char* buffer, size_t size, size_t nitems, void* userdata)
    {
        size_t realSize = size *nitems;
        return realSize;
    }
    static size_t GetCurlData(void *ptr, size_t size, size_t nmemb, void *data)
    {
        size_t reaSize = size * nmemb;
        auto buff = reinterpret_cast<Buffer*>(data);

        if (buff->filled + reaSize > buff->size) {
            return 0;
        }

        errno_t errorCode = memcpy_s(buff->data.get() + buff->filled, buff->size - buff->filled, ptr, reaSize);
        if (errorCode != EOK) {
            return reaSize;
        }
        buff->filled += reaSize;
        return reaSize;
    }
    std::string url_{""};
    CURL *curl_{nullptr};
    std::shared_ptr<Buffer> memoryBuffer_{nullptr};
};

#endif  /* __FILE_DOWNLOAD_H_ */
